Resize

将输入图像张量按指定插值方法缩放到目标尺寸。输入/输出均为 NHWC 格式: [batch, height, width, channel],缩放作用于 height、width 维,batch 与 channel 保持不变。

坐标变换

对输出像素坐标 \(x_{resized}\),先映射到输入浮点坐标 \(x_{orig}\)。设输入边长为 \(L_{in}\),输出边长为 \(L_{out}\),缩放比 \(s = L_{out} / L_{in}\), 则三种 coordinate_transform_mode_ 为:

\[\begin{split}\begin{aligned} \mathrm{ASYMMETRIC:} &\quad x_{orig} = \frac{x_{resized}}{s} \\ \mathrm{ALIGN\_CORNERS:} &\quad x_{orig} = x_{resized} \cdot \frac{L_{in} - 1}{L_{out} - 1} \\ \mathrm{HALF\_PIXEL:} &\quad x_{orig} = \max\left(0,\; \frac{x_{resized} + 0.5}{s} - 0.5\right) \end{aligned}\end{split}\]

高度方向同理。

插值方法

  1. NEAREST(最邻近)

    \(x_{orig}\)\(y_{orig}\) 取整得到输入像素索引后直接拷贝: ALIGN_CORNERS 时用 \(\mathrm{round}\),其余模式用 \(\mathrm{floor}\)

  2. BILINEAR(双线性,schema 中亦称 LINEAR)

    对浮点坐标 \(out\) 与输入长度 \(in\)

    \[\begin{split}\begin{aligned} bottom &= \max(0, \lfloor out \rfloor) \\ top &= \min(bottom + 1,\; in - 1) \\ w_{bottom} &= 1 - (out - bottom) \end{aligned}\end{split}\]

    先沿宽方向插值,再沿高方向插值:

    \[O[h, w, c] = I[y_b, x_l, c]\, w_y\, w_x + I[y_b, x_r, c]\, w_y\, (1 - w_x) + I[y_t, x_l, c]\, (1 - w_y)\, w_x + I[y_t, x_r, c]\, (1 - w_y)\, (1 - w_x)\]
  3. CUBIC(双三次)

    在每维取 4 个相邻点,权重由系数 \(a`(``cubic_coeff_`\),常用 \(-0.75\))决定:

    \[\begin{split}W(a, x) = \begin{cases} ((a+2)|x| - (a+3))|x|^2 + 1, & 0 \le |x| \le 1 \\ a|x|^3 - 5a|x|^2 + 8a|x| - 4a, & 1 < |x| \le 2 \\ 0, & \text{otherwise} \end{cases}\end{split}\]

    先对 4 行做水平加权,再对结果做垂直加权得到输出像素。

调用前需按 method_ 完成预处理:BILINEAR 调用 PrepareResizeBilinearCUBIC 调用 PrepareResizeBicubicNEAREST 无需预处理缓冲。

输入:
  • input - 输入数据的地址

  • param - 算子计算所需参数的结构体。其各成员见下述。

  • core_mask - 核掩码(仅共享存储版本使用)。

ResizeParameter定义:

 1typedef enum ResizeMethod {
 2    BILINEAR = 0,   // 双线性(对应 schema LINEAR)
 3    NEAREST = 1,    // 最邻近
 4    CUBIC = 2       // 双三次
 5} ResizeMethod;
 6
 7typedef enum CoordinateTransformMode {
 8    ASYMMETRIC = 0,
 9    ALIGN_CORNERS = 1,
10    HALF_PIXEL = 2
11} CoordinateTransformMode;
12
13typedef struct ResizeParameter {
14    int* input_shape_;                  // 输入形状 [N,H,W,C],需 4 * sizeof(int)
15    int* output_shape_;                 // 输出形状 [N,H,W,C],需 4 * sizeof(int)
16    int* x_lefts_;                      // 水平索引数组,非单个值;见下方分配说明
17    int* x_rights_;                     // 水平右邻索引数组(BILINEAR)
18    int* y_tops_;                       // 垂直索引数组,非单个值;见下方分配说明
19    int* y_bottoms_;                    // 垂直下邻索引数组(BILINEAR)
20    void* x_weights_;                   // 水平权重数组,非单个值;见下方分配说明
21    void* y_weights_;                   // 垂直权重数组,非单个值;见下方分配说明
22    void* line_buffers_;                // 插值中间行缓冲,非单个值;见下方分配说明
23    int method_;                        // ResizeMethod
24    int coordinate_transform_mode_;     // CoordinateTransformMode
25    float cubic_coeff_;                 // 双三次系数 a,仅 CUBIC 使用
26} ResizeParameter;

缓冲分配说明:

以上 x_lefts_ ~ line_buffers_ 均为**指针,指向需调用方预分配的数组**,不是单个标量。 设输出高宽为 \(H_{out}\)\(W_{out}\),通道为 \(C\),参与计算的核数为 \(N_{core}`(私有存储版本为 1),元素字节数为 :math:`S=\operatorname{sizeof}(T)\)

  • input_shape_ / output_shape_:各 4 个 int。

  • BILINEAR

    • x_lefts_ / x_rights_:各 \(W_{out}\) 个 int

    • y_tops_ / y_bottoms_:各 \(H_{out}\) 个 int

    • x_weights_\(W_{out}\) 个 float

    • y_weights_\(H_{out}\) 个 float

    • line_buffers_\(2 \times W_{out} \times C \times N_{core} \times S\) 字节(每核 2 行缓存)

  • CUBIC

    • x_lefts_\(4 \times W_{out}\) 个 int(每个输出列存 4 个邻域索引)

    • y_tops_\(4 \times H_{out}\) 个 int(每个输出行存 4 个邻域索引)

    • x_weights_\(4 \times W_{out}\) 个 float

    • y_weights_\(4 \times H_{out}\) 个 float

    • line_buffers_\(4 \times W_{out} \times C \times N_{core} \times S\) 字节(每核 4 行缓存)

    • x_rights_ / y_bottoms_:CUBIC 不使用,可不分配

  • NEAREST:上述预处理缓冲均可不分配。

输出:
  • output - 输出地址。

支持平台:

FT78NE MT7004

备注

  • FT78NE 支持 int8, fp32

  • MT7004 支持 fp16, fp32

共享存储版本:

void i8_resize_s(int8_t *input, int8_t *output, ResizeParameter *param, int core_mask)
void hp_resize_s(float16 *input, float16 *output, ResizeParameter *param, int core_mask)
void fp_resize_s(float *input, float *output, ResizeParameter *param, int core_mask)

C调用示例:

 1// MT7004 示例(共享存储多核,DDR 地址)
 2void TestResizeSMCFp32(int* input_shape, int* output_shape, int method,
 3                       int mode, float cubic_coeff, int core_mask) {
 4    int core_id = get_core_id();
 5    int core_num = GetCoreNum(core_mask);
 6    int logic_core_id = GetLogicCoreId(core_mask, core_id);
 7    float* input = (float*)0x88000000;
 8    float* output = (float*)0x98000000;
 9    ResizeParameter* param = (ResizeParameter*)0x90020000;
10    if (logic_core_id == 0) {
11        param->coordinate_transform_mode_ = mode;
12        param->method_ = method;
13        param->cubic_coeff_ = cubic_coeff;
14        param->input_shape_ = (int*)0x90030000;
15        memcpy(param->input_shape_, input_shape, sizeof(int) * 4);
16        param->output_shape_ = (int*)0x90040000;
17        memcpy(param->output_shape_, output_shape, sizeof(int) * 4);
18        param->line_buffers_ = (void*)0x91000000;
19        param->x_lefts_ = (int*)0x93000000;
20        param->x_rights_ = (int*)0x93100000;
21        param->y_bottoms_ = (int*)0x93200000;
22        param->y_tops_ = (int*)0x93300000;
23        param->x_weights_ = (void*)0x93400000;
24        param->y_weights_ = (void*)0x93500000;
25        if (method == BILINEAR) {
26            PrepareResizeBilinear(param);
27        } else if (method == CUBIC) {
28            PrepareResizeBicubic(param, cubic_coeff);
29        }
30    }
31    sys_bar(0, core_num);
32    fp_resize_s(input, output, param, core_mask);
33}
34
35void main() {
36    int input_shape[4] = {1, 8, 8, 4};
37    int output_shape[4] = {1, 16, 16, 4};
38    int method = BILINEAR;
39    int mode = ALIGN_CORNERS;
40    float cubic_coeff = -0.75f;
41    int core_mask = 0b1111;
42    TestResizeSMCFp32(input_shape, output_shape, method, mode, cubic_coeff, core_mask);
43}

私有存储版本:

void i8_resize_p(int8_t *input, int8_t *output, ResizeParameter *param)
void hp_resize_p(float16 *input, float16 *output, ResizeParameter *param)
void fp_resize_p(float *input, float *output, ResizeParameter *param)

C调用示例:

 1// MT7004 示例(私有存储单核,AM 地址)
 2void TestResizeAMFp32(int* input_shape, int* output_shape, int method,
 3                      int mode, float cubic_coeff) {
 4    float* input = (float*)0x10000000;
 5    float* output = (float*)0x10020000;
 6    ResizeParameter* param = (ResizeParameter*)0x10052000;
 7    param->coordinate_transform_mode_ = mode;
 8    param->method_ = method;
 9    param->cubic_coeff_ = cubic_coeff;
10    param->input_shape_ = (int*)0x10053000;
11    memcpy(param->input_shape_, input_shape, sizeof(int) * 4);
12    param->output_shape_ = (int*)0x10054000;
13    memcpy(param->output_shape_, output_shape, sizeof(int) * 4);
14    param->line_buffers_ = (void*)0x10055000;
15    param->x_lefts_ = (int*)0x10059000;
16    param->x_rights_ = (int*)0x1005D000;
17    param->y_bottoms_ = (int*)0x10061000;
18    param->y_tops_ = (int*)0x10065000;
19    param->x_weights_ = (void*)0x10069000;
20    param->y_weights_ = (void*)0x1006D000;
21    if (method == BILINEAR) {
22        PrepareResizeBilinear(param);
23    } else if (method == CUBIC) {
24        PrepareResizeBicubic(param, cubic_coeff);
25    }
26    fp_resize_p(input, output, param);
27}
28
29void main() {
30    int input_shape[4] = {1, 8, 8, 4};
31    int output_shape[4] = {1, 16, 16, 4};
32    int method = BILINEAR;
33    int mode = ALIGN_CORNERS;
34    float cubic_coeff = -0.75f;
35    TestResizeAMFp32(input_shape, output_shape, method, mode, cubic_coeff);
36}